5.2.4 Exercises

  1. Find all flights that
  1. Had an arrival delay of two or more hours

**

flights %>%
  filter(arr_delay >= 120)

Notice, that arr_delay is given in minutes.


  1. Flew to Houston (IAH or HOU)

**

flights %>%
  filter(dest %in% c("IAH", "HOU"))

  1. Were operated by United, American, or Delta

**

flights %>%
  filter(carrier %in% c("UA", "AA", "DL"))

  1. Departed in summer (July, August, and September)

**

flights %>%
  filter(month %in% 7:9)

  1. Arrived more than two hours late, but didn’t leave late

**

flights %>%
  filter(arr_delay > 120, dep_delay <= 0)

  1. Were delayed by at least an hour, but made up over 30 minutes in flight

**

flights %>%
  filter(dep_delay >= 60, dep_delay - arr_delay >= 30)

  1. Departed between midnight and 6am (inclusive)

**

flights %>%
  filter(dep_time == 2400 | dep_time <= 600)

  1. Another useful dplyr filtering helper is between(). What does it do? Can you use it to simplify the code needed to answer the previous challenges?

**

between(x, left, right) looks for the values smaller or equal than parameter left and bigger or equal than parameter right.

flights %>%
  filter(!between(dep_time, 601, 2399))

  1. How many flights have a missing dep_time? What other variables are missing? What might these rows represent?

**

Number of missing dep_times:

flights %>%
  filter(is.na(dep_time)) %>%
  nrow()
[1] 8255
# Alternativelly
sum(is.na(flights$dep_time))
[1] 8255

Check for NA’s:

purr
Error: object 'purr' not found

Number of occurrences with missing dep_time and dep_delay are same. Similar case is with air_time and arr_delay. Let’s check if this is coincidence.

flights %>%
  filter(is.na(dep_delay) & is.na(dep_time)) %>%
  nrow()
[1] 8255
flights %>%
  filter(is.na(dep_delay) & is.na(dep_time) & is.na(arr_delay) & is.na(air_time)) %>%
  nrow()
[1] 8255
flights %>%
  filter(is.na(arr_delay) & is.na(air_time)) %>%
  nrow()
[1] 9430

This is not coincidence. The flights without dep_time and/or dep_delay obviously did not happen. However, there are flights with no arr_delay or air_time delay that do have dep_delay and dep_time. These flights were probably with plains in the air at the time that the data is updated.


  1. Why is NA ^ 0 not missing? Why is NA | TRUE not missing? Why is FALSE & NA not missing? Can you figure out the general rule? (NA * 0 is a tricky counterexample!)

**

Any number on power of 0 is always 1. So is NA:

NA ^ 0
[1] 1
5 ^ 0
[1] 1
Inf ^ 0
[1] 1

TRUE or something else is always TRUE:

NA | TRUE
[1] TRUE
Inf | TRUE
[1] TRUE
7 | TRUE
[1] TRUE

FALSE or something else is always FALSE

FALSE & NA
[1] FALSE
FALSE & Inf
[1] FALSE
FALSE & 7
[1] FALSE

In mathematics is any number times 0 always 0. However, R has special values like Inf where Inf * 0 is undefined (NaN), and NA * 0 is unknown (NA).

NA * 0 
[1] NA
Inf * 0
[1] NaN
7 * 0
[1] 0

5.3.1 Exercises

  1. How could you use arrange() to sort all missing values to the start? (Hint: use is.na()).

**

flights %>%
  arrange(desc(is.na(dep_time)), dep_time)

  1. Sort flights to find the most delayed flights. Find the flights that left earliest.

**

Most delayed:

arrange(flights, desc(dep_delay))

Left earliest (ahead of the schedule):

arrange(flights, dep_delay)

Left earliest (left earliest w.r.t. the time of the day):

arrange(flights, dep_time)

  1. Sort flights to find the fastest flights.

**

arrange(flights, air_time)
arrange(flights, air_time/distance)

  1. Which flights travelled the longest? Which travelled the shortest?

**

Longest/shortest travelling w.r.t. the time spend in the air

arrange(flights, desc(air_time))
arrange(flights, air_time)

Longest/shortest travelling w.r.t. the distance

arrange(flights, desc(distance))
arrange(flights, distance)

5.4.1 Exercises

  1. Brainstorm as many ways as possible to select dep_time, dep_delay, arr_time, and arr_delay from flights.

**

select(flights,dep_time, dep_delay, arr_time, arr_delay)
select(flights,dep_time, dep_delay:arr_time, arr_delay)
select(flights,dep_time, dep_delay,starts_with("arr"))
select(flights,starts_with("dep"),arr_time, arr_delay)
select(flights,starts_with("dep"),starts_with("arr"))
select(flights,ends_with("delay"),dep_time,arr_time)
select(flights,dep_delay, arr_delay,ends_with("time"), -sched_dep_time, - sched_arr_time, - air_time)
select(flights,dep_delay, arr_delay,ends_with("time"), -starts_with("sched"), - air_time)
select(flights,ends_with("delay"),ends_with("time"), -sched_dep_time, - sched_arr_time, - air_time)
select(flights,ends_with("delay"),ends_with("time"), -starts_with("sched"), - air_time)
select(flights,4,6,7,9)
select(flights,4,6:7,9)
vars <- c("dep_time", "dep_delay", "arr_time", "arr_delay")
select(flights, one_of(vars))
select_(flights, .dots = vars)
select(flights, matches("dep"), matches("arr"), -matches("sched"), -carrier)
select(flights, contains("dep"), contains("arr"), -contains("sched"), -carrier)
select(flights, matches("^dep|^arr"))
select(flights, matches("time$|delay$"), -contains("sched"), -contains("air"))

  1. What happens if you include the name of a variable multiple times in a select() call?

**

select(flights, year, dep_time, year)

The second occurrence of the variable is ignored.


  1. What does the one_of() function do? Why might it be helpful in conjunction with this vector?
vars <- c("year", "month", "day", "dep_delay", "arr_delay")

**

select(flights, one_of(vars))
vars <- c("year", "month", "day", "dep_delay", "arr_delay","test_var")
select(flights, one_of(vars))
Unknown variables: `test_var`

one_off() selects all variables in a data set that are also listed in a vector containing variable names. If the vector contains names that are not variable names for the chosen set R will give a warning and process the known variable names.


  1. Does the result of running the following code surprise you? How do the select helpers deal with case by default? How can you change that default?
select(flights, contains("TIME"))

**

select(flights, contains("TIME", ignore.case = FALSE))

R is case sensitive, but function contains() default is set to ignore the case sensitivity.


5.5.2 Exercises

  1. Currently dep_time and sched_dep_time are convenient to look at, but hard to compute with because they’re not really continuous numbers. Convert them to a more convenient representation of number of minutes since midnight.

**

# convert conveniant hhmm formated integer to number of minutes since midnight
to_min <- function(x){
  x <- x %/% 100 * 60 + x %% 100
}
# Let's convert all time variables with this format (hhmm) to the minutes. It's handy to use it in the next exercises.
(flights_min <- flights %>%
  mutate(dep_time = to_min(dep_time),
         arr_time = to_min(arr_time),
         sched_dep_time = to_min(sched_dep_time),
         sched_arr_time = to_min(sched_arr_time)))

  1. Compare air_time with arr_time - dep_time. What do you expect to see? What do you see? What do you need to do to fix it?

**

(flights_min <- flights_min %>% 
   mutate(gate_to_gate_minutes = arr_time - dep_time))
flights_min %>%
  ggplot() +
  geom_freqpoly(aes(x = gate_to_gate_minutes - air_time), binwidth = 60)

flights_min %>%
  filter(near(gate_to_gate_minutes, air_time, 0.5)) %>%
  nrow()
[1] 196

One would expect that the difference between the arrival and departure (gate_to_gate_minutes) is equal to the airtime, but this is almost never the case. Most of the flights have longer gate to gate than airtime. This could be explained if the airtime is defined as time that a plane is in the air whereby the taxying from gate and to gate are not included.

Furthermore, a number of the differences between the gate to gate and air times are negative. As the plains cannot arrive before their departure. So, probably we are dealing with the overnight flights where the time is stretching over two days.

The two things need to happen:


  1. Compare dep_time, sched_dep_time, and dep_delay. How would you expect those three numbers to be related?
(flights_min <- flights_min %>% 
   mutate(calc_delay = dep_time - sched_dep_time))
flights_min %>%
  ggplot(aes(x = calc_delay - dep_delay)) +
  geom_freqpoly(bins = 60)

flights_min %>%
  filter(near(calc_delay, dep_delay, 0.5)) %>%
  nrow()
[1] 327314

I would expect that dep_delay is difference between the scheduled and departure time. Apparently, this is not always the case.

flights_min %>%
  filter(dep_delay != calc_delay,
         calc_delay > 0)

Checking the occurrences where departure and calculate delays are not equal reveals that in all these cases scheduled departure time is greater than departure time. Therefore, these flights seem to be the overnight flights!


  1. Find the 10 most delayed flights using a ranking function. How do you want to handle ties? Carefully read the documentation for min_rank().

**

flights %>%
  filter(min_rank(-dep_delay) %in% 1:10)  %>%
  arrange(desc(dep_delay))
# Alternativelly
flights %>%
  top_n(10, dep_delay) %>%
  arrange(desc(dep_delay))

  1. What does 1:3 + 1:10 return? Why?
(x <- 1:3)
[1] 1 2 3
(y <- 1:10)
 [1]  1  2  3  4  5  6  7  8  9 10
x+y
longer object length is not a multiple of shorter object length
 [1]  2  4  6  5  7  9  8 10 12 11

When summing up two vectors of different lengths the shorter vector will be recycled


  1. What trigonometric functions does R provide?

**

Sinus, cosinus tangens: sin(), cos(), tan()

Arc-sinus, cosinus tangens: asin(), acos(), atan(), atan2()

for parameters that are multiples of a half: cospi(), sinpi(), tanpi()


5.6.7 Exercises

  1. Brainstorm at least 5 different ways to assess the typical delay characteristics of a group of flights. Consider the following scenarios:
  1. A flight is 15 minutes early 50% of the time, and 15 minutes late 50% of the time.

**

Not very convenient as 50% is like a flip of the coin. Also, interval of +/-15mn is actually 30min period. Therefore, you cannot plan very well.


  1. A flight is always 10 minutes late.

**

Although it is bad that plain is late it is quite OK if you know this in advance. That way you will actually always be on (modified) time.


  1. A flight is 30 minutes early 50% of the time, and 30 minutes late 50% of the time.

**

This is same situation as in the first scenario, but the delay interval is even greater, i.e. 1 hour. That makes the flight vary unreliable.


  1. 99% of the time a flight is on time. 1% of the time it’s 2 hours late.

**

This might actually be quite acceptable, as this 2 hours makes an incident, rather than a rule.


Which is more important: arrival delay or departure delay?

**

Arrival delay is more important for the passages, as departure delay can be compensated by shorter air time and taxying. For the airport are both delays equally important because any delay can mix up the schedule and might impact the other flights. Although, early arrivals and departures are probably preferable to the late arrivals and departures.


  1. Come up with another approach that will give you the same output as not_cancelled %>% count(dest) and not_cancelled %>% count(tailnum, wt = distance) (without using count()).

**

Let’s say that not cancelled means that the flight has departure time (not NA).

not_cancelled <- flights %>%
  filter(!is.na(dep_time)) 
# First given option
not_cancelled %>% count(dest)
# Second given option
not_cancelled %>% count(tailnum, wt = distance)
# Another approaches
not_cancelled %>%
  group_by(dest) %>%
  summarise(n = n())
not_cancelled %>%
  group_by(dest) %>%
  tally()
not_cancelled %>%
  group_by(tailnum) %>%
  summarise(tot_distance = sum(distance))
not_cancelled %>%
  group_by(tailnum) %>%
  tally(wt = distance)
  1. Our definition of cancelled flights (is.na(dep_delay) | is.na(arr_delay) ) is slightly suboptimal. Why? Which is the most important column?

**

If the plain is cancelled it will not have departure nor it will have arrival delay. They both will be NA, just as departure time.

If the plain has departured but it does not have arrival time, the plain has left and it is either in the air or it has landed on unknown destination. In both cases this is not a cancelled but ongoing, crashed or diverged flight.

If the plain has arrival delay and it does not have departure delay ( i.e. departure delay is NA), than something went wrong with the administration. This case (data) should be ignored.

Therefore, departure delay is more reliable to be used for the definition of the cancelled flights.

flights %>%
  filter(is.na(dep_time) | is.na(dep_delay)) %>%
  select(contains("delay"), contains("time")) %>%
  map_dbl(~sum(is.na(.x)))
     dep_delay      arr_delay       dep_time sched_dep_time       arr_time sched_arr_time 
          8255           8255           8255              0           8255              0 
      air_time      time_hour 
          8255              0 
flights %>%
  filter(is.na(arr_delay)) %>%
  select(contains("delay"), contains("time")) %>%
  map_dbl(~sum(is.na(.x)))
     dep_delay      arr_delay       dep_time sched_dep_time       arr_time sched_arr_time 
          8255           9430           8255              0           8713              0 
      air_time      time_hour 
          9430              0 

  1. Look at the number of cancelled flights per day. Is there a pattern? Is the proportion of cancelled flights related to the average delay?

**

flights %>%
  group_by(year, month, day) %>%
  summarise(avg_canc = mean(is.na(dep_time)),
            avg_dep = mean(dep_delay, na.rm = T)) %>%
  ggplot(aes(x = avg_dep, y = avg_canc)) +
  geom_point() +
  geom_smooth() +
  labs(x = "Avg departure delay", y = "Avg proportion of cancelled flights")

In general, the longer the delay the greater proportion of cancelled flights.


  1. Which carrier has the worst delays? Challenge: can you disentangle the effects of bad airports vs. bad carriers? Why/why not? (Hint: think about flights %>% group_by(carrier, dest) %>% summarise(n()))

**

Worst delays per carrier:

We can distinguish the average from the incidental delays. The worst incidental delays are not those of the carriers that have the worst average delays.

Furthermore, the carriers with the worst departure delays tend to be also the carriers with the worst arrival delay. This was to be expected. However, not all of the carriers are evenly good in catching up once they have departed with a delay.

Let’s analyse bad airports vs. bad carriers relationship.

flights %>%
  group_by(carrier, origin, dest) %>%
  summarise(avg_dep_delay = mean(dep_delay, na.rm = TRUE),
            avg_arr_delay = mean(arr_delay, na.rm = T)) %>%
  ggplot(aes(x = avg_dep_delay, y = avg_arr_delay)) +
  geom_point() +
  geom_smooth() +
  labs(x = "Avg departure delay", y = "vg arrival delay")

flights %>%
  group_by(carrier, origin, dest) %>%
  summarise(avg_dep_delay = mean(dep_delay, na.rm = TRUE),
            avg_arr_delay = mean(arr_delay, na.rm = T)) %>%
  filter(avg_dep_delay > 35 | avg_arr_delay > 25) %>%
  ggplot(aes(x = origin, y = dest)) +
  geom_point() +
  facet_grid(~carrier)

Looking at the average departure vs. average arrival delays per carrier we can see that most of the carriers have similar pattern. When taking out only those with extreme average departure delays or average arrival delays it becomes clear that EWR, JFK and LGA are the airports with worst track or departure delays. This pattern cannot be seen on the arrival airports. Also, only four carriers: 9E, EV, OO and UA, cover all the worst delays.


  1. What does the sort argument to count() do. When might you use it?

**

It is an alternative to the arrange. Use it with vectors. Possibly easier when you want to order NA’s first or as parameter to a function as count when you want to count and order on the count.


5.7.1 Exercises

  1. Refer back to the table of useful mutate and filtering functions. Describe how each operation changes when you combine it with grouping.

**

Filtering functions are executed per group. The filtering per group might not result in the same results as when applying it per whole set. For example, filtering where mean value of group or higher is not same as filtering per mean value of the data set and higher.

Similar holds for mutate.


  1. Which plane (tailnum) has the worst on-time record?

**

flights %>%
  group_by(tailnum) %>%
  summarise(mean_arr_delay = mean(arr_delay, na.rm = TRUE)) %>%
  top_n(1)
Selecting by mean_arr_delay

  1. What time of day should you fly if you want to avoid delays as much as possible?

**

flights %>%
  group_by(hour) %>%
  summarise(mean_delay = mean(dep_delay > 0, na.rm=TRUE)) %>%
  ggplot(aes(x = hour, y = mean_delay)) +
  geom_smooth()

Flying early in the morning seems to be the best option.


  1. For each destination, compute the total minutes of delay. For each, flight, compute the proportion of the total delay for its destination.

**

flight_delays <- flights %>%
  mutate(arr_delay = ifelse(arr_delay > 0, arr_delay, 0)) %>%
  group_by(dest) %>%
  summarise(tot_dest_delays = sum(arr_delay, na.rm = TRUE)) %>%
  arrange(desc(tot_dest_delays))
flights %>%
  mutate(arr_delay = ifelse(arr_delay > 0, arr_delay, 0)) %>%
  group_by(dest, tailnum) %>%
  summarise(arr_delay = sum(arr_delay, na.rm = TRUE)) %>%
  left_join(flight_delays, by = "dest") %>%
  mutate(prop_delay = arr_delay / tot_dest_delays) %>%
  arrange(desc(tailnum))

  1. Delays are typically temporally correlated: even once the problem that caused the initial delay has been resolved, later flights are delayed to allow earlier flights to leave. Using lag() explore how the delay of a flight is related to the delay of the immediately preceding flight.

**

flights %>%
  arrange(sched_dep_time) %>%
  mutate(prev_delay = lag(dep_delay)) %>%
  ggplot(aes(x = dep_delay, y = prev_delay)) +
  geom_point() +
  geom_smooth()

flights %>%
  arrange(sched_dep_time) %>%
  mutate(prev_delay = lag(dep_delay)) %>%
  filter(dep_delay < 450,
         dep_delay > 10) %>%
  ggplot(aes(x = dep_delay, y = prev_delay)) +
  geom_point() +
  geom_smooth()

The very short departure times do not have clear pattern. However, when we look at the departures longer than 10min it is clear that the longer departure delays the more chance that the preceding plain has been delayed. Somewhere after the 250min of delay, this influence of the previous delays seems to remain constant, and it declines after the delays of 350 min.


  1. Look at each destination. Can you find flights that are suspiciously fast? (i.e. flights that represent a potential data entry error). Compute the air time a flight relative to the shortest flight to that destination. Which flights were most delayed in the air?

**

flights %>%
  mutate(speed = (air_time %/% 100 * 60 * 60 + air_time %% 100 * 60) / distance) %>%
  group_by(dest) %>%
  mutate(max_speed = max(speed, na.rm = TRUE),
         med_speed = median(speed, na.rm = TRUE),
         prop = max_speed / med_speed) %>%
  arrange(desc(prop))

flights <- flights %>% mutate(
  dep_time = hour * 60 + minute,
  arr_time = (arr_time %/% 100) * 60 + (arr_time %% 100),
  airtime2 = arr_time - dep_time,
  dep_sched = dep_time + dep_delay
)

ggplot(flights, aes(dep_sched)) + geom_histogram(binwidth = 60)
ggplot(flights, aes(dep_sched %% 60)) + geom_histogram(binwidth = 1)
ggplot(flights, aes(air_time - airtime2)) + geom_histogram()

  1. Find all destinations that are flown by at least two carriers. Use that information to rank the carriers.

**


  1. For each plane, count the number of flights before the first delay of greater than 1 hour.

**

flights %>%
  mutate(is_delayed = arr_delay > 60) %>%
  group_by(tailnum) %>%
  arrange(arr_time) %>%
  mutate(first_delay = ifelse(is_delayed == TRUE, is_delayed, NA),
         first_delay = row_number(first_delay)) %>%
  filter(is.na(first_delay)) %>%
  group_by(tailnum) %>%
  summarise(n = n()) %>%
  arrange(desc(n))
################
flights %>%
  mutate(dep_date = time_hour) %>%
  group_by(tailnum) %>%
  arrange(dep_date) %>%
  mutate(cumulative = !cumany(arr_delay > 60)) %>%
  filter(cumulative == T) %>%
  tally(sort = TRUE)
LS0tCnRpdGxlOiAiNSBEYXRhIHRyYW5zZm9ybWF0aW9uIgpvdXRwdXQ6Cmh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgpgYGB7ciBzZXR1cCwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykKCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBjb21tZW50ID0gIiM+IiwKICBjb2xsYXBzZSA9IFRSVUUKKQpgYGAKCiMgNS4yLjQgRXhlcmNpc2VzCgoxLiAgRmluZCBhbGwgZmxpZ2h0cyB0aGF0CgphLiBIYWQgYW4gYXJyaXZhbCBkZWxheSBvZiB0d28gb3IgbW9yZSBob3VycwoKKioKCmBgYHtyIDUuMi40LjEuYX0KZmxpZ2h0cyAlPiUKICBmaWx0ZXIoYXJyX2RlbGF5ID49IDEyMCkKYGBgCgpOb3RpY2UsIHRoYXQgYXJyX2RlbGF5IGlzIGdpdmVuIGluIG1pbnV0ZXMuCgoqKioKCmIuIEZsZXcgdG8gSG91c3RvbiAoYElBSGAgb3IgYEhPVWApCgoqKgoKYGBge3IgNS4yLjQuMS5ifQpmbGlnaHRzICU+JQogIGZpbHRlcihkZXN0ICVpbiUgYygiSUFIIiwgIkhPVSIpKQpgYGAKCioqKgoKYy4gV2VyZSBvcGVyYXRlZCBieSBVbml0ZWQsIEFtZXJpY2FuLCBvciBEZWx0YQoKKioKCmBgYHtyIDUuMi40LjEuY30KZmxpZ2h0cyAlPiUKICBmaWx0ZXIoY2FycmllciAlaW4lIGMoIlVBIiwgIkFBIiwgIkRMIikpCmBgYAoKCioqKgoKZC4gRGVwYXJ0ZWQgaW4gc3VtbWVyIChKdWx5LCBBdWd1c3QsIGFuZCBTZXB0ZW1iZXIpCgoqKgoKYGBge3IgNS4yLjQuMS5kfQpmbGlnaHRzICU+JQogIGZpbHRlcihtb250aCAlaW4lIDc6OSkKYGBgCgoqKioKCmUuIEFycml2ZWQgbW9yZSB0aGFuIHR3byBob3VycyBsYXRlLCBidXQgZGlkbid0IGxlYXZlIGxhdGUKCioqCgpgYGB7ciA1LjIuNC4xLmV9CmZsaWdodHMgJT4lCiAgZmlsdGVyKGFycl9kZWxheSA+IDEyMCwgZGVwX2RlbGF5IDw9IDApCmBgYAoKKioqCgpmLiBXZXJlIGRlbGF5ZWQgYnkgYXQgbGVhc3QgYW4gaG91ciwgYnV0IG1hZGUgdXAgb3ZlciAzMCBtaW51dGVzIGluIGZsaWdodAoKKioKCmBgYHtyIDUuMi40LjEuZn0KZmxpZ2h0cyAlPiUKICBmaWx0ZXIoZGVwX2RlbGF5ID49IDYwLCBkZXBfZGVsYXkgLSBhcnJfZGVsYXkgPj0gMzApCmBgYAoKKioqCgpnLiBEZXBhcnRlZCBiZXR3ZWVuIG1pZG5pZ2h0IGFuZCA2YW0gKGluY2x1c2l2ZSkKCioqCgpgYGB7ciA1LjIuNC4xLmd9CmZsaWdodHMgJT4lCiAgZmlsdGVyKGRlcF90aW1lID09IDI0MDAgfCBkZXBfdGltZSA8PSA2MDApCmBgYAoKKioqCgoyLiAgQW5vdGhlciB1c2VmdWwgZHBseXIgZmlsdGVyaW5nIGhlbHBlciBpcyBgYmV0d2VlbigpYC4gV2hhdCBkb2VzIGl0IGRvPyBDYW4geW91IHVzZSBpdCB0byBzaW1wbGlmeSB0aGUgY29kZSBuZWVkZWQgdG8gYW5zd2VyIHRoZSBwcmV2aW91cyBjaGFsbGVuZ2VzPwoKKioKCmBiZXR3ZWVuKHgsIGxlZnQsIHJpZ2h0KWAgbG9va3MgZm9yIHRoZSB2YWx1ZXMgc21hbGxlciBvciBlcXVhbCB0aGFuIHBhcmFtZXRlciBgbGVmdGAgYW5kIGJpZ2dlciBvciBlcXVhbCB0aGFuIHBhcmFtZXRlciBgcmlnaHRgLgoKYGBge3IgNS4yLjQuMn0KZmxpZ2h0cyAlPiUKICBmaWx0ZXIoIWJldHdlZW4oZGVwX3RpbWUsIDYwMSwgMjM5OSkpCmBgYAoKKioqCgozLiAgSG93IG1hbnkgZmxpZ2h0cyBoYXZlIGEgbWlzc2luZyBgZGVwX3RpbWVgPyBXaGF0IG90aGVyIHZhcmlhYmxlcyBhcmUgCm1pc3Npbmc/IFdoYXQgbWlnaHQgdGhlc2Ugcm93cyByZXByZXNlbnQ/CgoqKgoKTnVtYmVyIG9mIG1pc3NpbmcgZGVwX3RpbWVzOgoKYGBge3IgNS4yLjQuMy4xfQpmbGlnaHRzICU+JQogIGZpbHRlcihpcy5uYShkZXBfdGltZSkpICU+JQogIG5yb3coKQoKIyBBbHRlcm5hdGl2ZWxseQpzdW0oaXMubmEoZmxpZ2h0cyRkZXBfdGltZSkpCmBgYAoKQ2hlY2sgZm9yIE5BJ3M6CgpgYGB7ciA1LjIuNC4zLjIsIG1lc3NhZ2UgPSBGQUxTRX0Kc3VtbWFyeShmbGlnaHRzKQoKIyBBbHRlcm5hdGl2ZWxseQpsaWJyYXJ5KHB1cnJyKQptYXBfZGJsKGZsaWdodHMsIH5zdW0oaXMubmEoLngpKSkKYGBgCgpOdW1iZXIgb2Ygb2NjdXJyZW5jZXMgd2l0aCBtaXNzaW5nIGRlcF90aW1lIGFuZCBkZXBfZGVsYXkgYXJlIHNhbWUuIFNpbWlsYXIgY2FzZSBpcyB3aXRoIGFpcl90aW1lIGFuZCBhcnJfZGVsYXkuIExldCdzIGNoZWNrIGlmIHRoaXMgaXMgY29pbmNpZGVuY2UuCgpgYGB7ciA1LjIuNC4zLjN9CmZsaWdodHMgJT4lCiAgZmlsdGVyKGlzLm5hKGRlcF9kZWxheSkgJiBpcy5uYShkZXBfdGltZSkpICU+JQogIG5yb3coKQoKZmxpZ2h0cyAlPiUKICBmaWx0ZXIoaXMubmEoZGVwX2RlbGF5KSAmIGlzLm5hKGRlcF90aW1lKSAmIGlzLm5hKGFycl9kZWxheSkgJiBpcy5uYShhaXJfdGltZSkpICU+JQogIG5yb3coKQoKZmxpZ2h0cyAlPiUKICBmaWx0ZXIoaXMubmEoYXJyX2RlbGF5KSAmIGlzLm5hKGFpcl90aW1lKSkgJT4lCiAgbnJvdygpCmBgYAoKVGhpcyBpcyBub3QgY29pbmNpZGVuY2UuIFRoZSBmbGlnaHRzIHdpdGhvdXQgZGVwX3RpbWUgYW5kL29yIGRlcF9kZWxheSBvYnZpb3VzbHkgZGlkIG5vdCBoYXBwZW4uIEhvd2V2ZXIsIHRoZXJlIGFyZSBmbGlnaHRzIHdpdGggbm8gYXJyX2RlbGF5IG9yIGFpcl90aW1lIGRlbGF5IHRoYXQgZG8gaGF2ZSBkZXBfZGVsYXkgYW5kIGRlcF90aW1lLiBUaGVzZSBmbGlnaHRzIHdlcmUgcHJvYmFibHkgd2l0aCBwbGFpbnMgaW4gdGhlIGFpciBhdCB0aGUgdGltZSB0aGF0IHRoZSBkYXRhIGlzIHVwZGF0ZWQuCgoqKioKCjQuICBXaHkgaXMgYE5BIF4gMGAgbm90IG1pc3Npbmc/IFdoeSBpcyBgTkEgfCBUUlVFYCBub3QgbWlzc2luZz8gV2h5IGlzIGBGQUxTRSAmIE5BYCBub3QgbWlzc2luZz8gQ2FuIHlvdSBmaWd1cmUgb3V0IHRoZSBnZW5lcmFsIHJ1bGU/ICAoYE5BICogMGAgaXMgYSB0cmlja3kgY291bnRlcmV4YW1wbGUhKQoKKioKCkFueSBudW1iZXIgb24gcG93ZXIgb2YgMCBpcyBhbHdheXMgMS4gU28gaXMgTkE6CgpgYGB7ciA1LjIuNC40LjF9Ck5BIF4gMAo1IF4gMApJbmYgXiAwCmBgYAoKVFJVRSBvciBzb21ldGhpbmcgZWxzZSBpcyBhbHdheXMgVFJVRToKCmBgYHtyIDUuMi40LjQuMn0KTkEgfCBUUlVFCkluZiB8IFRSVUUKNyB8IFRSVUUKYGBgCgpGQUxTRSBvciBzb21ldGhpbmcgZWxzZSBpcyBhbHdheXMgRkFMU0UKCmBgYHtyIDUuMi40LjQuM30KRkFMU0UgJiBOQQpGQUxTRSAmIEluZgpGQUxTRSAmIDcKYGBgCgpJbiBtYXRoZW1hdGljcyBpcyBhbnkgbnVtYmVyIHRpbWVzIDAgYWx3YXlzIDAuIEhvd2V2ZXIsIFIgaGFzIHNwZWNpYWwgdmFsdWVzIGxpa2UgSW5mIHdoZXJlIEluZiAqIDAgaXMgdW5kZWZpbmVkIChOYU4pLCBhbmQgTkEgKiAwIGlzIHVua25vd24gKE5BKS4KCmBgYHtyIDUuMi40LjQuNH0KTkEgKiAwIApJbmYgKiAwCjcgKiAwCmBgYAoKKioqCgo1LjMuMSBFeGVyY2lzZXMKCjEuICBIb3cgY291bGQgeW91IHVzZSBgYXJyYW5nZSgpYCB0byBzb3J0IGFsbCBtaXNzaW5nIHZhbHVlcyB0byB0aGUgc3RhcnQ/CihIaW50OiB1c2UgYGlzLm5hKClgKS4KCioqCgpgYGB7ciA1LjMuMS4xfQpmbGlnaHRzICU+JQogIGFycmFuZ2UoZGVzYyhpcy5uYShkZXBfdGltZSkpLCBkZXBfdGltZSkKYGBgCgoqKioKCjIuICBTb3J0IGBmbGlnaHRzYCB0byBmaW5kIHRoZSBtb3N0IGRlbGF5ZWQgZmxpZ2h0cy4gRmluZCB0aGUgZmxpZ2h0cyB0aGF0IGxlZnQgZWFybGllc3QuCgoqKgoKTW9zdCBkZWxheWVkOgoKYGBge3IgNS4zLjEuMi4xfQphcnJhbmdlKGZsaWdodHMsIGRlc2MoZGVwX2RlbGF5KSkKYGBgCgpMZWZ0IGVhcmxpZXN0IChhaGVhZCBvZiB0aGUgc2NoZWR1bGUpOgoKYGBge3IgNS4zLjEuMi4yfQphcnJhbmdlKGZsaWdodHMsIGRlcF9kZWxheSkKYGBgCgpMZWZ0IGVhcmxpZXN0IChsZWZ0IGVhcmxpZXN0IHcuci50LiB0aGUgdGltZSBvZiB0aGUgZGF5KToKCmBgYHtyIDUuMy4xLjIuM30KYXJyYW5nZShmbGlnaHRzLCBkZXBfdGltZSkKYGBgCgoqKioKMy4gIFNvcnQgYGZsaWdodHNgIHRvIGZpbmQgdGhlIGZhc3Rlc3QgZmxpZ2h0cy4KCioqCgoqIFRoZSBmYXN0ZXN0IGZsaWdodHMgaW4gdGVybXMgb2YgdGhlIHNob3J0ZXN0IHRpbWUgaW4gdGhlIGFpcgoKYGBge3IgNS4zLjEuMy4xfQphcnJhbmdlKGZsaWdodHMsIGFpcl90aW1lKQpgYGAKCiogVGhlIGZhc3Rlc3QgZmxpZ2h0cyBpbiB0ZXJtcyBvZiBzcGVlZAoKYGBge3IgNS4zLjEuMy4yfQphcnJhbmdlKGZsaWdodHMsIGFpcl90aW1lL2Rpc3RhbmNlKQpgYGAKCioqKgoKNC4gIFdoaWNoIGZsaWdodHMgdHJhdmVsbGVkIHRoZSBsb25nZXN0PyBXaGljaCB0cmF2ZWxsZWQgdGhlIHNob3J0ZXN0PwoKKioKCkxvbmdlc3Qvc2hvcnRlc3QgdHJhdmVsbGluZyB3LnIudC4gdGhlIHRpbWUgc3BlbmQgaW4gdGhlIGFpcgoKYGBge3IgNS4zLjEuNC4xfQphcnJhbmdlKGZsaWdodHMsIGRlc2MoYWlyX3RpbWUpKQphcnJhbmdlKGZsaWdodHMsIGFpcl90aW1lKQpgYGAKCkxvbmdlc3Qvc2hvcnRlc3QgdHJhdmVsbGluZyB3LnIudC4gdGhlIGRpc3RhbmNlCgpgYGB7ciA1LjMuMS40LjJ9CmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhkaXN0YW5jZSkpCmFycmFuZ2UoZmxpZ2h0cywgZGlzdGFuY2UpCmBgYAoKKioqCgojIDUuNC4xIEV4ZXJjaXNlcwoKMS4gIEJyYWluc3Rvcm0gYXMgbWFueSB3YXlzIGFzIHBvc3NpYmxlIHRvIHNlbGVjdCBgZGVwX3RpbWVgLCBgZGVwX2RlbGF5YCwKYGFycl90aW1lYCwgYW5kIGBhcnJfZGVsYXlgIGZyb20gYGZsaWdodHNgLgoKKioKCmBgYHtyIDUuNC4xLjF9CnNlbGVjdChmbGlnaHRzLGRlcF90aW1lLCBkZXBfZGVsYXksIGFycl90aW1lLCBhcnJfZGVsYXkpCnNlbGVjdChmbGlnaHRzLGRlcF90aW1lLCBkZXBfZGVsYXk6YXJyX3RpbWUsIGFycl9kZWxheSkKc2VsZWN0KGZsaWdodHMsZGVwX3RpbWUsIGRlcF9kZWxheSxzdGFydHNfd2l0aCgiYXJyIikpCnNlbGVjdChmbGlnaHRzLHN0YXJ0c193aXRoKCJkZXAiKSxhcnJfdGltZSwgYXJyX2RlbGF5KQpzZWxlY3QoZmxpZ2h0cyxzdGFydHNfd2l0aCgiZGVwIiksc3RhcnRzX3dpdGgoImFyciIpKQpzZWxlY3QoZmxpZ2h0cyxlbmRzX3dpdGgoImRlbGF5IiksZGVwX3RpbWUsYXJyX3RpbWUpCnNlbGVjdChmbGlnaHRzLGRlcF9kZWxheSwgYXJyX2RlbGF5LGVuZHNfd2l0aCgidGltZSIpLCAtc2NoZWRfZGVwX3RpbWUsIC0gc2NoZWRfYXJyX3RpbWUsIC0gYWlyX3RpbWUpCnNlbGVjdChmbGlnaHRzLGRlcF9kZWxheSwgYXJyX2RlbGF5LGVuZHNfd2l0aCgidGltZSIpLCAtc3RhcnRzX3dpdGgoInNjaGVkIiksIC0gYWlyX3RpbWUpCnNlbGVjdChmbGlnaHRzLGVuZHNfd2l0aCgiZGVsYXkiKSxlbmRzX3dpdGgoInRpbWUiKSwgLXNjaGVkX2RlcF90aW1lLCAtIHNjaGVkX2Fycl90aW1lLCAtIGFpcl90aW1lKQpzZWxlY3QoZmxpZ2h0cyxlbmRzX3dpdGgoImRlbGF5IiksZW5kc193aXRoKCJ0aW1lIiksIC1zdGFydHNfd2l0aCgic2NoZWQiKSwgLSBhaXJfdGltZSkKc2VsZWN0KGZsaWdodHMsNCw2LDcsOSkKc2VsZWN0KGZsaWdodHMsNCw2OjcsOSkKdmFycyA8LSBjKCJkZXBfdGltZSIsICJkZXBfZGVsYXkiLCAiYXJyX3RpbWUiLCAiYXJyX2RlbGF5IikKc2VsZWN0KGZsaWdodHMsIG9uZV9vZih2YXJzKSkKc2VsZWN0XyhmbGlnaHRzLCAuZG90cyA9IHZhcnMpCnNlbGVjdChmbGlnaHRzLCBtYXRjaGVzKCJkZXAiKSwgbWF0Y2hlcygiYXJyIiksIC1tYXRjaGVzKCJzY2hlZCIpLCAtY2FycmllcikKc2VsZWN0KGZsaWdodHMsIGNvbnRhaW5zKCJkZXAiKSwgY29udGFpbnMoImFyciIpLCAtY29udGFpbnMoInNjaGVkIiksIC1jYXJyaWVyKQpzZWxlY3QoZmxpZ2h0cywgbWF0Y2hlcygiXmRlcHxeYXJyIikpCnNlbGVjdChmbGlnaHRzLCBtYXRjaGVzKCJ0aW1lJHxkZWxheSQiKSwgLWNvbnRhaW5zKCJzY2hlZCIpLCAtY29udGFpbnMoImFpciIpKQpgYGAKCioqKgoKMi4gIFdoYXQgaGFwcGVucyBpZiB5b3UgaW5jbHVkZSB0aGUgbmFtZSBvZiBhIHZhcmlhYmxlIG11bHRpcGxlIHRpbWVzIGluCmEgYHNlbGVjdCgpYCBjYWxsPwoKKioKCmBgYHtyIDUuNC4xLjJ9CnNlbGVjdChmbGlnaHRzLCB5ZWFyLCBkZXBfdGltZSwgeWVhcikKYGBgCgpUaGUgc2Vjb25kIG9jY3VycmVuY2Ugb2YgdGhlIHZhcmlhYmxlIGlzIGlnbm9yZWQuCgoqKioKCjMuICBXaGF0IGRvZXMgdGhlIGBvbmVfb2YoKWAgZnVuY3Rpb24gZG8/IFdoeSBtaWdodCBpdCBiZSBoZWxwZnVsIGluIGNvbmp1bmN0aW9uCndpdGggdGhpcyB2ZWN0b3I/CgpgYGB7cn0KdmFycyA8LSBjKCJ5ZWFyIiwgIm1vbnRoIiwgImRheSIsICJkZXBfZGVsYXkiLCAiYXJyX2RlbGF5IikKYGBgCgoqKgoKYGBge3IgNS40LjEuM30Kc2VsZWN0KGZsaWdodHMsIG9uZV9vZih2YXJzKSkKdmFycyA8LSBjKCJ5ZWFyIiwgIm1vbnRoIiwgImRheSIsICJkZXBfZGVsYXkiLCAiYXJyX2RlbGF5IiwidGVzdF92YXIiKQpzZWxlY3QoZmxpZ2h0cywgb25lX29mKHZhcnMpKQpgYGAKCm9uZV9vZmYoKSBzZWxlY3RzIGFsbCB2YXJpYWJsZXMgaW4gYSBkYXRhIHNldCB0aGF0IGFyZSBhbHNvIGxpc3RlZCBpbiBhIHZlY3RvciBjb250YWluaW5nIHZhcmlhYmxlIG5hbWVzLiBJZiB0aGUgdmVjdG9yIGNvbnRhaW5zIG5hbWVzIHRoYXQgYXJlIG5vdCB2YXJpYWJsZSBuYW1lcyBmb3IgdGhlIGNob3NlbiBzZXQgUiB3aWxsIGdpdmUgYSB3YXJuaW5nIGFuZCBwcm9jZXNzIHRoZSBrbm93biB2YXJpYWJsZSBuYW1lcy4KCioqKgoKNC4gIERvZXMgdGhlIHJlc3VsdCBvZiBydW5uaW5nIHRoZSBmb2xsb3dpbmcgY29kZSBzdXJwcmlzZSB5b3U/ICBIb3cgZG8gdGhlCnNlbGVjdCBoZWxwZXJzIGRlYWwgd2l0aCBjYXNlIGJ5IGRlZmF1bHQ/IEhvdyBjYW4geW91IGNoYW5nZSB0aGF0IGRlZmF1bHQ/CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpzZWxlY3QoZmxpZ2h0cywgY29udGFpbnMoIlRJTUUiKSkKYGBgCgoqKgoKYGBge3IgNS40LjEuNH0Kc2VsZWN0KGZsaWdodHMsIGNvbnRhaW5zKCJUSU1FIiwgaWdub3JlLmNhc2UgPSBGQUxTRSkpCmBgYAoKUiBpcyBjYXNlIHNlbnNpdGl2ZSwgYnV0IGZ1bmN0aW9uIGNvbnRhaW5zKCkgZGVmYXVsdCBpcyBzZXQgdG8gaWdub3JlIHRoZSBjYXNlIHNlbnNpdGl2aXR5LgoKKioqCgojIDUuNS4yIEV4ZXJjaXNlcwoKMS4gIEN1cnJlbnRseSBgZGVwX3RpbWVgIGFuZCBgc2NoZWRfZGVwX3RpbWVgIGFyZSBjb252ZW5pZW50IHRvIGxvb2sgYXQsIGJ1dCBoYXJkIHRvIGNvbXB1dGUgd2l0aCBiZWNhdXNlIHRoZXkncmUgbm90IHJlYWxseSBjb250aW51b3VzIG51bWJlcnMuIENvbnZlcnQgdGhlbSB0byBhIG1vcmUgY29udmVuaWVudCByZXByZXNlbnRhdGlvbiBvZiBudW1iZXIgb2YgbWludXRlcyBzaW5jZSBtaWRuaWdodC4KCioqCgpgYGB7ciA1LjUuMi4xfQojIGNvbnZlcnQgY29udmVuaWVudCBoaG1tIGZvcm1hdHRlZCBpbnRlZ2VyIHRvIG51bWJlciBvZiBtaW51dGVzIHNpbmNlIG1pZG5pZ2h0CnRvX21pbiA8LSBmdW5jdGlvbih4KXsKICB4IDwtIHggJS8lIDEwMCAqIDYwICsgeCAlJSAxMDAKfQoKIyBMZXQncyBjb252ZXJ0IGFsbCB0aW1lIHZhcmlhYmxlcyB3aXRoIHRoaXMgZm9ybWF0IChoaG1tKSB0byB0aGUgbWludXRlcy4gSXQncyBoYW5keSB0byB1c2UgaXQgaW4gdGhlIG5leHQgZXhlcmNpc2VzLgooZmxpZ2h0c19taW4gPC0gZmxpZ2h0cyAlPiUKICAgIG11dGF0ZShkZXBfdGltZSA9IHRvX21pbihkZXBfdGltZSksCiAgICAgICAgICAgYXJyX3RpbWUgPSB0b19taW4oYXJyX3RpbWUpLAogICAgICAgICAgIHNjaGVkX2RlcF90aW1lID0gdG9fbWluKHNjaGVkX2RlcF90aW1lKSwKICAgICAgICAgICBzY2hlZF9hcnJfdGltZSA9IHRvX21pbihzY2hlZF9hcnJfdGltZSkpKQpgYGAKCioqKgoKMi4gIENvbXBhcmUgYGFpcl90aW1lYCB3aXRoIGBhcnJfdGltZSAtIGRlcF90aW1lYC4gV2hhdCBkbyB5b3UgZXhwZWN0IHRvIHNlZT8KV2hhdCBkbyB5b3Ugc2VlPyBXaGF0IGRvIHlvdSBuZWVkIHRvIGRvIHRvIGZpeCBpdD8KCioqCgpgYGB7ciA1LjUuMi4yfQooZmxpZ2h0c19taW4gPC0gZmxpZ2h0c19taW4gJT4lIAogICBtdXRhdGUoZ2F0ZV90b19nYXRlX21pbnV0ZXMgPSBhcnJfdGltZSAtIGRlcF90aW1lKSkKCmZsaWdodHNfbWluICU+JQogIGdncGxvdCgpICsKICBnZW9tX2ZyZXFwb2x5KGFlcyh4ID0gZ2F0ZV90b19nYXRlX21pbnV0ZXMgLSBhaXJfdGltZSksIGJpbndpZHRoID0gNjApCgpmbGlnaHRzX21pbiAlPiUKICBmaWx0ZXIobmVhcihnYXRlX3RvX2dhdGVfbWludXRlcywgYWlyX3RpbWUsIDAuNSkpICU+JQogIG5yb3coKQpgYGAKCk9uZSB3b3VsZCBleHBlY3QgdGhhdCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBhcnJpdmFsIGFuZCBkZXBhcnR1cmUgKGdhdGVfdG9fZ2F0ZV9taW51dGVzKSBpcyBlcXVhbCB0byB0aGUgYWlydGltZSwgYnV0IHRoaXMgaXMgYWxtb3N0IG5ldmVyIHRoZSBjYXNlLiBNb3N0IG9mIHRoZSBmbGlnaHRzIGhhdmUgbG9uZ2VyIGdhdGUgdG8gZ2F0ZSB0aGFuIGFpcnRpbWUuIFRoaXMgY291bGQgYmUgZXhwbGFpbmVkIGlmIHRoZSBhaXJ0aW1lIGlzIGRlZmluZWQgYXMgdGltZSB0aGF0IGEgcGxhbmUgaXMgaW4gdGhlIGFpciB3aGVyZWJ5IHRoZSB0YXh5aW5nIGZyb20gZ2F0ZSBhbmQgdG8gZ2F0ZSBhcmUgbm90IGluY2x1ZGVkLiAKCkZ1cnRoZXJtb3JlLCBhIG51bWJlciBvZiB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgZ2F0ZSB0byBnYXRlIGFuZCBhaXIgdGltZXMgYXJlIG5lZ2F0aXZlLiBBcyB0aGUgcGxhaW5zIGNhbm5vdCBhcnJpdmUgYmVmb3JlIHRoZWlyIGRlcGFydHVyZS4gU28sIHByb2JhYmx5IHdlIGFyZSBkZWFsaW5nIHdpdGggdGhlIG92ZXJuaWdodCBmbGlnaHRzIHdoZXJlIHRoZSB0aW1lIGlzIHN0cmV0Y2hpbmcgb3ZlciB0d28gZGF5cy4KClRoZSB0d28gdGhpbmdzIG5lZWQgdG8gaGFwcGVuOgoKLSBXZSBuZWVkIHRvIGRpc3Rpbmd1aXNoIGJldHdlZW4gcHVyZSBhaXJ0aW1lIGFuZCBnYXRlIHRvIGdhdGUgdGltZXMuCgotIFdlIG5lZWQgdG8gaW5jbHVkZSBkYXRlIHRvIGdldCBjb3JyZWN0IGdhdGUgdG8gZ2F0ZSBkYXRlLXRpbWVzIGZvciB0aGUgb3Zlcm5pZ2h0IGZsaWdodHMKCioqKgoKMy4gIENvbXBhcmUgYGRlcF90aW1lYCwgYHNjaGVkX2RlcF90aW1lYCwgYW5kIGBkZXBfZGVsYXlgLiBIb3cgd291bGQgeW91CmV4cGVjdCB0aG9zZSB0aHJlZSBudW1iZXJzIHRvIGJlIHJlbGF0ZWQ/CgpgYGB7ciA1LjUuMi4zLjF9CihmbGlnaHRzX21pbiA8LSBmbGlnaHRzX21pbiAlPiUgCiAgIG11dGF0ZShjYWxjX2RlbGF5ID0gZGVwX3RpbWUgLSBzY2hlZF9kZXBfdGltZSkpCgpmbGlnaHRzX21pbiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBjYWxjX2RlbGF5IC0gZGVwX2RlbGF5KSkgKwogIGdlb21fZnJlcXBvbHkoYmlucyA9IDYwKQoKZmxpZ2h0c19taW4gJT4lCiAgZmlsdGVyKG5lYXIoY2FsY19kZWxheSwgZGVwX2RlbGF5LCAwLjUpKSAlPiUKICBucm93KCkKYGBgCgpJIHdvdWxkIGV4cGVjdCB0aGF0IGRlcF9kZWxheSBpcyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHNjaGVkdWxlZCBhbmQgZGVwYXJ0dXJlIHRpbWUuIEFwcGFyZW50bHksIHRoaXMgaXMgbm90IGFsd2F5cyB0aGUgY2FzZS4gCgpgYGB7ciA1LjUuMi4zLjJ9CmZsaWdodHNfbWluICU+JQogIGZpbHRlcihkZXBfZGVsYXkgIT0gY2FsY19kZWxheSwKICAgICAgICAgY2FsY19kZWxheSA+IDApCmBgYAoKQ2hlY2tpbmcgdGhlIG9jY3VycmVuY2VzIHdoZXJlIGRlcGFydHVyZSBhbmQgY2FsY3VsYXRlIGRlbGF5cyBhcmUgbm90IGVxdWFsIHJldmVhbHMgdGhhdCBpbiBhbGwgdGhlc2UgY2FzZXMgc2NoZWR1bGVkIGRlcGFydHVyZSB0aW1lIGlzIGdyZWF0ZXIgdGhhbiBkZXBhcnR1cmUgdGltZS4gVGhlcmVmb3JlLCB0aGVzZSBmbGlnaHRzIHNlZW0gdG8gYmUgdGhlIG92ZXJuaWdodCBmbGlnaHRzIQoKKioqCgo0LiAgRmluZCB0aGUgMTAgbW9zdCBkZWxheWVkIGZsaWdodHMgdXNpbmcgYSByYW5raW5nIGZ1bmN0aW9uLiBIb3cgZG8geW91IHdhbnQgCnRvIGhhbmRsZSB0aWVzPyBDYXJlZnVsbHkgcmVhZCB0aGUgZG9jdW1lbnRhdGlvbiBmb3IgYG1pbl9yYW5rKClgLgoKKioKCmBgYHtyIDUuNS4yLjR9CmZsaWdodHMgJT4lCiAgZmlsdGVyKG1pbl9yYW5rKC1kZXBfZGVsYXkpICVpbiUgMToxMCkgICU+JQogIGFycmFuZ2UoZGVzYyhkZXBfZGVsYXkpKQoKIyBBbHRlcm5hdGl2ZWxseQpmbGlnaHRzICU+JQogIHRvcF9uKDEwLCBkZXBfZGVsYXkpICU+JQogIGFycmFuZ2UoZGVzYyhkZXBfZGVsYXkpKQpgYGAKCioqKgoKNS4gIFdoYXQgZG9lcyBgMTozICsgMToxMGAgcmV0dXJuPyBXaHk/CgpgYGB7ciA1LjUuMi41fQooeCA8LSAxOjMpCih5IDwtIDE6MTApCngreQpgYGAKCldoZW4gc3VtbWluZyB1cCB0d28gdmVjdG9ycyBvZiBkaWZmZXJlbnQgbGVuZ3RocyB0aGUgc2hvcnRlciB2ZWN0b3Igd2lsbCBiZSByZWN5Y2xlZAoKKioqCgo2LiAgV2hhdCB0cmlnb25vbWV0cmljIGZ1bmN0aW9ucyBkb2VzIFIgcHJvdmlkZT8KCioqCgpTaW51cywgY29zaW51cyB0YW5nZW5zOiBzaW4oKSwgY29zKCksIHRhbigpCgpBcmMtc2ludXMsIGNvc2ludXMgdGFuZ2VuczogYXNpbigpLCBhY29zKCksIGF0YW4oKSwgYXRhbjIoKQoKZm9yIHBhcmFtZXRlcnMgdGhhdCBhcmUgbXVsdGlwbGVzIG9mIGEgaGFsZjogY29zcGkoKSwgc2lucGkoKSwgdGFucGkoKQoKKioqCgojIDUuNi43IEV4ZXJjaXNlcwoKMS4gIEJyYWluc3Rvcm0gYXQgbGVhc3QgNSBkaWZmZXJlbnQgd2F5cyB0byBhc3Nlc3MgdGhlIHR5cGljYWwgZGVsYXkgCmNoYXJhY3RlcmlzdGljcyBvZiBhIGdyb3VwIG9mIGZsaWdodHMuIENvbnNpZGVyIHRoZSBmb2xsb3dpbmcgc2NlbmFyaW9zOgoKYS4gQSBmbGlnaHQgaXMgMTUgbWludXRlcyBlYXJseSA1MCUgb2YgdGhlIHRpbWUsIGFuZCAxNSBtaW51dGVzIGxhdGUgNTAlIG9mIAp0aGUgdGltZS4KCioqCgpOb3QgdmVyeSBjb252ZW5pZW50IGFzIDUwJSBpcyBsaWtlIGEgZmxpcCBvZiB0aGUgY29pbi4gQWxzbywgaW50ZXJ2YWwgb2YgKy8tMTVtbiBpcyBhY3R1YWxseSAzMG1pbiBwZXJpb2QuIFRoZXJlZm9yZSwgeW91IGNhbm5vdCBwbGFuIHZlcnkgd2VsbC4KCioqKgoKYi4gQSBmbGlnaHQgaXMgYWx3YXlzIDEwIG1pbnV0ZXMgbGF0ZS4KCioqCgpBbHRob3VnaCBpdCBpcyBiYWQgdGhhdCBwbGFpbiBpcyBsYXRlIGl0IGlzIHF1aXRlIE9LIGlmIHlvdSBrbm93IHRoaXMgaW4gYWR2YW5jZS4gVGhhdCB3YXkgeW91IHdpbGwgYWN0dWFsbHkgYWx3YXlzIGJlIG9uIChtb2RpZmllZCkgdGltZS4KCioqKgoKYy4gQSBmbGlnaHQgaXMgMzAgbWludXRlcyBlYXJseSA1MCUgb2YgdGhlIHRpbWUsIGFuZCAzMCBtaW51dGVzIGxhdGUgNTAlIG9mIAp0aGUgdGltZS4KCioqCgpUaGlzIGlzIHNhbWUgc2l0dWF0aW9uIGFzIGluIHRoZSBmaXJzdCBzY2VuYXJpbywgYnV0IHRoZSBkZWxheSBpbnRlcnZhbCBpcyBldmVuIGdyZWF0ZXIsIGkuZS4gMSBob3VyLiBUaGF0IG1ha2VzIHRoZSBmbGlnaHQgdmFyeSB1bnJlbGlhYmxlLgoKKioqCgpkLiA5OSUgb2YgdGhlIHRpbWUgYSBmbGlnaHQgaXMgb24gdGltZS4gMSUgb2YgdGhlIHRpbWUgaXQncyAyIGhvdXJzIGxhdGUuCgoqKgoKVGhpcyBtaWdodCBhY3R1YWxseSBiZSBxdWl0ZSBhY2NlcHRhYmxlLCBhcyB0aGlzIDIgaG91cnMgbWFrZXMgYW4gaW5jaWRlbnQsIHJhdGhlciB0aGFuIGEgcnVsZS4KCioqKgoKV2hpY2ggaXMgbW9yZSBpbXBvcnRhbnQ6IGFycml2YWwgZGVsYXkgb3IgZGVwYXJ0dXJlIGRlbGF5PwoKKioKCkFycml2YWwgZGVsYXkgaXMgbW9yZSBpbXBvcnRhbnQgZm9yIHRoZSBwYXNzYWdlcywgYXMgZGVwYXJ0dXJlIGRlbGF5IGNhbiBiZSBjb21wZW5zYXRlZCBieSBzaG9ydGVyIGFpciB0aW1lIGFuZCB0YXh5aW5nLiBGb3IgdGhlIGFpcnBvcnQgYXJlIGJvdGggZGVsYXlzIGVxdWFsbHkgaW1wb3J0YW50IGJlY2F1c2UgYW55IGRlbGF5IGNhbiBtaXggdXAgdGhlIHNjaGVkdWxlIGFuZCBtaWdodCBpbXBhY3QgdGhlIG90aGVyIGZsaWdodHMuIEFsdGhvdWdoLCBlYXJseSBhcnJpdmFscyBhbmQgZGVwYXJ0dXJlcyBhcmUgcHJvYmFibHkgcHJlZmVyYWJsZSB0byB0aGUgbGF0ZSBhcnJpdmFscyBhbmQgZGVwYXJ0dXJlcy4KCioqKgoKMi4gIENvbWUgdXAgd2l0aCBhbm90aGVyIGFwcHJvYWNoIHRoYXQgd2lsbCBnaXZlIHlvdSB0aGUgc2FtZSBvdXRwdXQgYXMgCmBub3RfY2FuY2VsbGVkICU+JSBjb3VudChkZXN0KWAgYW5kIApgbm90X2NhbmNlbGxlZCAlPiUgY291bnQodGFpbG51bSwgd3QgPSBkaXN0YW5jZSlgICh3aXRob3V0IHVzaW5nIApgY291bnQoKWApLgoKKioKCkxldCdzIHNheSB0aGF0IG5vdCBjYW5jZWxsZWQgbWVhbnMgdGhhdCB0aGUgZmxpZ2h0IGhhcyBkZXBhcnR1cmUgdGltZSAobm90IE5BKS4KCmBgYHtyIDUuNi43LjJ9Cm5vdF9jYW5jZWxsZWQgPC0gZmxpZ2h0cyAlPiUKICBmaWx0ZXIoIWlzLm5hKGRlcF90aW1lKSkgCgojIEZpcnN0IGdpdmVuIG9wdGlvbgpub3RfY2FuY2VsbGVkICU+JSBjb3VudChkZXN0KQoKIyBBbm90aGVyIGFwcHJvYWNoZXMKbm90X2NhbmNlbGxlZCAlPiUKICBncm91cF9ieShkZXN0KSAlPiUKICBzdW1tYXJpc2UobiA9IG4oKSkKCm5vdF9jYW5jZWxsZWQgJT4lCiAgZ3JvdXBfYnkoZGVzdCkgJT4lCiAgdGFsbHkoKQoKIyBTZWNvbmQgZ2l2ZW4gb3B0aW9uCm5vdF9jYW5jZWxsZWQgJT4lIGNvdW50KHRhaWxudW0sIHd0ID0gZGlzdGFuY2UpCgojIEFsdGVybmF0aXZlIGFwcHJvYWNoZXMKCm5vdF9jYW5jZWxsZWQgJT4lCiAgZ3JvdXBfYnkodGFpbG51bSkgJT4lCiAgc3VtbWFyaXNlKHRvdF9kaXN0YW5jZSA9IHN1bShkaXN0YW5jZSkpCgpub3RfY2FuY2VsbGVkICU+JQogIGdyb3VwX2J5KHRhaWxudW0pICU+JQogIHRhbGx5KHd0ID0gZGlzdGFuY2UpCmBgYAoKCjMuICBPdXIgZGVmaW5pdGlvbiBvZiBjYW5jZWxsZWQgZmxpZ2h0cyAoYGlzLm5hKGRlcF9kZWxheSkgfCBpcy5uYShhcnJfZGVsYXkpYAopIGlzIHNsaWdodGx5IHN1Ym9wdGltYWwuIFdoeT8gV2hpY2ggaXMgdGhlIG1vc3QgaW1wb3J0YW50IGNvbHVtbj8KCioqCgpJZiB0aGUgcGxhaW4gaXMgY2FuY2VsbGVkIGl0IHdpbGwgbm90IGhhdmUgZGVwYXJ0dXJlIG5vciBpdCB3aWxsIGhhdmUgYXJyaXZhbCBkZWxheS4gVGhleSBib3RoIHdpbGwgYmUgTkEsIGp1c3QgYXMgZGVwYXJ0dXJlIHRpbWUuCgpJZiB0aGUgcGxhaW4gaGFzIGRlcGFydHVyZWQgYnV0IGl0IGRvZXMgbm90IGhhdmUgYXJyaXZhbCB0aW1lLCB0aGUgcGxhaW4gaGFzIGxlZnQgYW5kIGl0IGlzIGVpdGhlciBpbiB0aGUgYWlyIG9yIGl0IGhhcyBsYW5kZWQgb24gdW5rbm93biBkZXN0aW5hdGlvbi4gSW4gYm90aCBjYXNlcyB0aGlzIGlzIG5vdCBhIGNhbmNlbGxlZCBidXQgb25nb2luZywgY3Jhc2hlZCBvciBkaXZlcmdlZCBmbGlnaHQuCgpJZiB0aGUgcGxhaW4gaGFzIGFycml2YWwgZGVsYXkgYW5kIGl0IGRvZXMgbm90IGhhdmUgZGVwYXJ0dXJlIGRlbGF5ICggaS5lLiBkZXBhcnR1cmUgZGVsYXkgaXMgTkEpLCB0aGFuIHNvbWV0aGluZyB3ZW50IHdyb25nIHdpdGggdGhlIGFkbWluaXN0cmF0aW9uLiBUaGlzIGNhc2UgKGRhdGEpIHNob3VsZCBiZSBpZ25vcmVkLgoKVGhlcmVmb3JlLCBkZXBhcnR1cmUgZGVsYXkgaXMgbW9yZSByZWxpYWJsZSB0byBiZSB1c2VkIGZvciB0aGUgZGVmaW5pdGlvbiBvZiB0aGUgY2FuY2VsbGVkIGZsaWdodHMuCgoKYGBge3IgNS42LjcuM30KZmxpZ2h0cyAlPiUKICBmaWx0ZXIoaXMubmEoZGVwX3RpbWUpIHwgaXMubmEoZGVwX2RlbGF5KSkgJT4lCiAgc2VsZWN0KGNvbnRhaW5zKCJkZWxheSIpLCBjb250YWlucygidGltZSIpKSAlPiUKICBtYXBfZGJsKH5zdW0oaXMubmEoLngpKSkKCmZsaWdodHMgJT4lCiAgZmlsdGVyKGlzLm5hKGFycl9kZWxheSkpICU+JQogIHNlbGVjdChjb250YWlucygiZGVsYXkiKSwgY29udGFpbnMoInRpbWUiKSkgJT4lCiAgbWFwX2RibCh+c3VtKGlzLm5hKC54KSkpCmBgYAoKKioqCgo0LiAgTG9vayBhdCB0aGUgbnVtYmVyIG9mIGNhbmNlbGxlZCBmbGlnaHRzIHBlciBkYXkuIElzIHRoZXJlIGEgcGF0dGVybj8KSXMgdGhlIHByb3BvcnRpb24gb2YgY2FuY2VsbGVkIGZsaWdodHMgcmVsYXRlZCB0byB0aGUgYXZlcmFnZSBkZWxheT8KCioqCgpgYGB7ciA1LjYuNy40fQpmbGlnaHRzICU+JQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JQogIHN1bW1hcmlzZShhdmdfY2FuYyA9IG1lYW4oaXMubmEoZGVwX3RpbWUpKSwKICAgICAgICAgICAgYXZnX2RlcCA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFQpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhdmdfZGVwLCB5ID0gYXZnX2NhbmMpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aCgpICsKICBsYWJzKHggPSAiQXZnIGRlcGFydHVyZSBkZWxheSIsIHkgPSAiQXZnIHByb3BvcnRpb24gb2YgY2FuY2VsbGVkIGZsaWdodHMiKQpgYGAKCkluIGdlbmVyYWwsIHRoZSBsb25nZXIgdGhlIGRlbGF5IHRoZSBncmVhdGVyIHByb3BvcnRpb24gb2YgY2FuY2VsbGVkIGZsaWdodHMuCgoqKioKCjUuICBXaGljaCBjYXJyaWVyIGhhcyB0aGUgd29yc3QgZGVsYXlzPyBDaGFsbGVuZ2U6IGNhbiB5b3UgZGlzZW50YW5nbGUgdGhlCmVmZmVjdHMgb2YgYmFkIGFpcnBvcnRzIHZzLiBiYWQgY2FycmllcnM/IFdoeS93aHkgbm90PyAoSGludDogdGhpbmsgYWJvdXQKYGZsaWdodHMgJT4lIGdyb3VwX2J5KGNhcnJpZXIsIGRlc3QpICU+JSBzdW1tYXJpc2UobigpKWApCgoqKgoKV29yc3QgZGVsYXlzIHBlciBjYXJyaWVyOgoKYGBge3IgNS42LjcuNS4xfQojIFdvcnN0IGRlcGFydHVyZSBkZWxheXMgcGVyIGNhcnJpZXIKZmxpZ2h0cyAlPiUKICBncm91cF9ieShjYXJyaWVyKSAlPiUKICBzdW1tYXJpc2UobWF4X2RlcF9kZWxheSA9IG1heChkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpICU+JQogIGFycmFuZ2UoZGVzYyhtYXhfZGVwX2RlbGF5KSkKCiMgV29yc3QgYXZlcmFnZSBkZXBhcnR1cmUgZGVsYXlzIHBlciBjYXJyaWVyCmZsaWdodHMgJT4lCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lCiAgc3VtbWFyaXNlKGF2Z19kZXBfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKGF2Z19kZXBfZGVsYXkpKQoKIyBXb3JzdCBhcnJpdmFsIGRlbGF5cyBwZXIgY2FycmllcgpmbGlnaHRzICU+JQogIGdyb3VwX2J5KGNhcnJpZXIpICU+JQogIHN1bW1hcmlzZShtYXhfYXJyX2RlbGF5ID0gbWF4KGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKG1heF9hcnJfZGVsYXkpKQoKIyBXb3JzdCBhdmVyYWdlIGFycml2YWwgZGVsYXlzIHBlciBjYXJyaWVyCmZsaWdodHMgJT4lCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lCiAgc3VtbWFyaXNlKGF2Z19hcnJfZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKGF2Z19hcnJfZGVsYXkpKQpgYGAKCldlIGNhbiBkaXN0aW5ndWlzaCB0aGUgYXZlcmFnZSBmcm9tIHRoZSBpbmNpZGVudGFsIGRlbGF5cy4gVGhlIHdvcnN0IGluY2lkZW50YWwgZGVsYXlzIGFyZSBub3QgdGhvc2Ugb2YgdGhlIGNhcnJpZXJzIHRoYXQgaGF2ZSB0aGUgd29yc3QgYXZlcmFnZSBkZWxheXMuCgpGdXJ0aGVybW9yZSwgdGhlIGNhcnJpZXJzIHdpdGggdGhlIHdvcnN0IGRlcGFydHVyZSBkZWxheXMgdGVuZCB0byBiZSBhbHNvIHRoZSBjYXJyaWVycyB3aXRoIHRoZSB3b3JzdCBhcnJpdmFsIGRlbGF5LiBUaGlzIHdhcyB0byBiZSBleHBlY3RlZC4gSG93ZXZlciwgbm90IGFsbCBvZiB0aGUgY2FycmllcnMgYXJlIGV2ZW5seSBnb29kIGluIGNhdGNoaW5nIHVwIG9uY2UgdGhleSBoYXZlIGRlcGFydGVkIHdpdGggYSBkZWxheS4KCkxldCdzIGFuYWx5c2UgYmFkIGFpcnBvcnRzIHZzLiBiYWQgY2FycmllcnMgcmVsYXRpb25zaGlwLgoKYGBge3IgNS42LjcuNS4yfQpmbGlnaHRzICU+JQogIGdyb3VwX2J5KGNhcnJpZXIsIG9yaWdpbiwgZGVzdCkgJT4lCiAgc3VtbWFyaXNlKGF2Z19kZXBfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgYXZnX2Fycl9kZWxheSA9IG1lYW4oYXJyX2RlbGF5LCBuYS5ybSA9IFQpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhdmdfZGVwX2RlbGF5LCB5ID0gYXZnX2Fycl9kZWxheSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkgKwogIGxhYnMoeCA9ICJBdmcgZGVwYXJ0dXJlIGRlbGF5IiwgeSA9ICJBdmcgYXJyaXZhbCBkZWxheSIpCgoKZmxpZ2h0cyAlPiUKICBncm91cF9ieShjYXJyaWVyLCBvcmlnaW4sIGRlc3QpICU+JQogIHN1bW1hcmlzZShhdmdfZGVwX2RlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGF2Z19hcnJfZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUKSkgJT4lCiAgZmlsdGVyKGF2Z19kZXBfZGVsYXkgPiAzNSB8IGF2Z19hcnJfZGVsYXkgPiAyNSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gb3JpZ2luLCB5ID0gZGVzdCkpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQofmNhcnJpZXIpCmBgYAoKTG9va2luZyBhdCB0aGUgYXZlcmFnZSBkZXBhcnR1cmUgdnMuIGF2ZXJhZ2UgYXJyaXZhbCBkZWxheXMgcGVyIGNhcnJpZXIgd2UgY2FuIHNlZSB0aGF0IG1vc3Qgb2YgdGhlIGNhcnJpZXJzIGhhdmUgc2ltaWxhciBwYXR0ZXJuLiBXaGVuIHRha2luZyBvdXQgb25seSB0aG9zZSB3aXRoIGV4dHJlbWUgYXZlcmFnZSBkZXBhcnR1cmUgZGVsYXlzIG9yIGF2ZXJhZ2UgYXJyaXZhbCBkZWxheXMgaXQgYmVjb21lcyBjbGVhciB0aGF0IEVXUiwgSkZLIGFuZCBMR0EgYXJlIHRoZSBhaXJwb3J0cyB3aXRoIHdvcnN0IHRyYWNrIG9yIGRlcGFydHVyZSBkZWxheXMuIFRoaXMgcGF0dGVybiBjYW5ub3QgYmUgc2VlbiBvbiB0aGUgYXJyaXZhbCBhaXJwb3J0cy4gQWxzbywgb25seSBmb3VyIGNhcnJpZXJzOiA5RSwgRVYsIE9PIGFuZCBVQSwgY292ZXIgYWxsIHRoZSB3b3JzdCBkZWxheXMuCgoqKioKCjEwLiAgV2hhdCBkb2VzIHRoZSBgc29ydGAgYXJndW1lbnQgdG8gYGNvdW50KClgIGRvLiBXaGVuIG1pZ2h0IHlvdSB1c2UgaXQ/CgoqKgoKSXQgaXMgYW4gYWx0ZXJuYXRpdmUgdG8gdGhlIGFycmFuZ2UuIFVzZSBpdCB3aXRoIHZlY3RvcnMuIFBvc3NpYmx5IGVhc2llciB3aGVuIHlvdSB3YW50IHRvIG9yZGVyIE5BJ3MgZmlyc3Qgb3IgYXMgcGFyYW1ldGVyIHRvIGEgZnVuY3Rpb24gYXMgY291bnQgd2hlbiB5b3Ugd2FudCB0byBjb3VudCBhbmQgb3JkZXIgb24gdGhlIGNvdW50LgoKKioqCgojIDUuNy4xIEV4ZXJjaXNlcwoKMS4gIFJlZmVyIGJhY2sgdG8gdGhlIHRhYmxlIG9mIHVzZWZ1bCBtdXRhdGUgYW5kIGZpbHRlcmluZyBmdW5jdGlvbnMuIApEZXNjcmliZSBob3cgZWFjaCBvcGVyYXRpb24gY2hhbmdlcyB3aGVuIHlvdSBjb21iaW5lIGl0IHdpdGggZ3JvdXBpbmcuCgoqKgoKRmlsdGVyaW5nIGZ1bmN0aW9ucyBhcmUgZXhlY3V0ZWQgcGVyIGdyb3VwLiBUaGUgZmlsdGVyaW5nIHBlciBncm91cCBtaWdodCBub3QgcmVzdWx0IGluIHRoZSBzYW1lIHJlc3VsdHMgYXMgd2hlbiBhcHBseWluZyBpdCBwZXIgd2hvbGUgc2V0LiBGb3IgZXhhbXBsZSwgZmlsdGVyaW5nIHdoZXJlIG1lYW4gdmFsdWUgb2YgZ3JvdXAgb3IgaGlnaGVyIGlzIG5vdCBzYW1lIGFzIGZpbHRlcmluZyBwZXIgbWVhbiB2YWx1ZSBvZiB0aGUgZGF0YSBzZXQgYW5kIGhpZ2hlci4KClNpbWlsYXIgaG9sZHMgZm9yIG11dGF0ZS4KCioqKgoKMi4gIFdoaWNoIHBsYW5lIChgdGFpbG51bWApIGhhcyB0aGUgd29yc3Qgb24tdGltZSByZWNvcmQ/CgoqKgoKYGBge3IgNS43LjEuMn0KZmxpZ2h0cyAlPiUKICBncm91cF9ieSh0YWlsbnVtKSAlPiUKICBzdW1tYXJpc2UobWVhbl9hcnJfZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgdG9wX24oMSkKYGBgCgoqKioKCjMuICBXaGF0IHRpbWUgb2YgZGF5IHNob3VsZCB5b3UgZmx5IGlmIHlvdSB3YW50IHRvIGF2b2lkIGRlbGF5cyBhcyBtdWNoCmFzIHBvc3NpYmxlPwoKKioKCmBgYHtyIDUuNy4xLjN9CmZsaWdodHMgJT4lCiAgZ3JvdXBfYnkoaG91cikgJT4lCiAgc3VtbWFyaXNlKG1lYW5fZGVsYXkgPSBtZWFuKGRlcF9kZWxheSA+IDAsIG5hLnJtPVRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBob3VyLCB5ID0gbWVhbl9kZWxheSkpICsKICBnZW9tX3Ntb290aCgpCmBgYAoKRmx5aW5nIGVhcmx5IGluIHRoZSBtb3JuaW5nIHNlZW1zIHRvIGJlIHRoZSBiZXN0IG9wdGlvbi4KCioqKgoKNC4gIEZvciBlYWNoIGRlc3RpbmF0aW9uLCBjb21wdXRlIHRoZSB0b3RhbCBtaW51dGVzIG9mIGRlbGF5LiBGb3IgZWFjaCwgCmZsaWdodCwgY29tcHV0ZSB0aGUgcHJvcG9ydGlvbiBvZiB0aGUgdG90YWwgZGVsYXkgZm9yIGl0cyBkZXN0aW5hdGlvbi4KCioqIAoKYGBge3IgNS43LjEuNH0KZmxpZ2h0X2RlbGF5cyA8LSBmbGlnaHRzICU+JQogIG11dGF0ZShhcnJfZGVsYXkgPSBpZmVsc2UoYXJyX2RlbGF5ID4gMCwgYXJyX2RlbGF5LCAwKSkgJT4lCiAgZ3JvdXBfYnkoZGVzdCkgJT4lCiAgc3VtbWFyaXNlKHRvdF9kZXN0X2RlbGF5cyA9IHN1bShhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkpICU+JQogIGFycmFuZ2UoZGVzYyh0b3RfZGVzdF9kZWxheXMpKQoKZmxpZ2h0cyAlPiUKICBtdXRhdGUoYXJyX2RlbGF5ID0gaWZlbHNlKGFycl9kZWxheSA+IDAsIGFycl9kZWxheSwgMCkpICU+JQogIGdyb3VwX2J5KGRlc3QsIHRhaWxudW0pICU+JQogIHN1bW1hcmlzZShhcnJfZGVsYXkgPSBzdW0oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpKSAlPiUKICBsZWZ0X2pvaW4oZmxpZ2h0X2RlbGF5cywgYnkgPSAiZGVzdCIpICU+JQogIG11dGF0ZShwcm9wX2RlbGF5ID0gYXJyX2RlbGF5IC8gdG90X2Rlc3RfZGVsYXlzKSAlPiUKICBhcnJhbmdlKGRlc2ModGFpbG51bSkpCmBgYAoKKioqCgo1LiAgRGVsYXlzIGFyZSB0eXBpY2FsbHkgdGVtcG9yYWxseSBjb3JyZWxhdGVkOiBldmVuIG9uY2UgdGhlIHByb2JsZW0gdGhhdApjYXVzZWQgdGhlIGluaXRpYWwgZGVsYXkgaGFzIGJlZW4gcmVzb2x2ZWQsIGxhdGVyIGZsaWdodHMgYXJlIGRlbGF5ZWQgCnRvIGFsbG93IGVhcmxpZXIgZmxpZ2h0cyB0byBsZWF2ZS4gVXNpbmcgYGxhZygpYCBleHBsb3JlIGhvdyB0aGUgZGVsYXkKb2YgYSBmbGlnaHQgaXMgcmVsYXRlZCB0byB0aGUgZGVsYXkgb2YgdGhlIGltbWVkaWF0ZWx5IHByZWNlZGluZyBmbGlnaHQuCgoqKgoKYGBge3IgNS43LjEuNX0KZmxpZ2h0cyAlPiUKICBhcnJhbmdlKHNjaGVkX2RlcF90aW1lKSAlPiUKICBtdXRhdGUocHJldl9kZWxheSA9IGxhZyhkZXBfZGVsYXkpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkZXBfZGVsYXksIHkgPSBwcmV2X2RlbGF5KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoKQoKZmxpZ2h0cyAlPiUKICBhcnJhbmdlKHNjaGVkX2RlcF90aW1lKSAlPiUKICBtdXRhdGUocHJldl9kZWxheSA9IGxhZyhkZXBfZGVsYXkpKSAlPiUKICBmaWx0ZXIoZGVwX2RlbGF5IDwgNDUwLAogICAgICAgICBkZXBfZGVsYXkgPiAxMCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZGVwX2RlbGF5LCB5ID0gcHJldl9kZWxheSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkKYGBgCgpUaGUgdmVyeSBzaG9ydCBkZXBhcnR1cmUgdGltZXMgZG8gbm90IGhhdmUgY2xlYXIgcGF0dGVybi4gSG93ZXZlciwgd2hlbiB3ZSBsb29rIGF0IHRoZSBkZXBhcnR1cmVzIGxvbmdlciB0aGFuIDEwbWluIGl0IGlzIGNsZWFyIHRoYXQgdGhlIGxvbmdlciBkZXBhcnR1cmUgZGVsYXlzIHRoZSBtb3JlIGNoYW5jZSB0aGF0IHRoZSBwcmVjZWRpbmcgcGxhaW4gaGFzIGJlZW4gZGVsYXllZC4gU29tZXdoZXJlIGFmdGVyIHRoZSAyNTBtaW4gb2YgZGVsYXksIHRoaXMgaW5mbHVlbmNlIG9mIHRoZSBwcmV2aW91cyBkZWxheXMgc2VlbXMgdG8gcmVtYWluIGNvbnN0YW50LCBhbmQgaXQgZGVjbGluZXMgYWZ0ZXIgdGhlIGRlbGF5cyBvZiAzNTAgbWluLgoKKioqCgo2LiAgTG9vayBhdCBlYWNoIGRlc3RpbmF0aW9uLiBDYW4geW91IGZpbmQgZmxpZ2h0cyB0aGF0IGFyZSBzdXNwaWNpb3VzbHkKZmFzdD8gKGkuZS4gZmxpZ2h0cyB0aGF0IHJlcHJlc2VudCBhIHBvdGVudGlhbCBkYXRhIGVudHJ5IGVycm9yKS4gQ29tcHV0ZQp0aGUgYWlyIHRpbWUgYSBmbGlnaHQgcmVsYXRpdmUgdG8gdGhlIHNob3J0ZXN0IGZsaWdodCB0byB0aGF0IGRlc3RpbmF0aW9uLgpXaGljaCBmbGlnaHRzIHdlcmUgbW9zdCBkZWxheWVkIGluIHRoZSBhaXI/CgoqKgoKYGBge3IgNS43LjEuNn0KZmxpZ2h0cyAlPiUKICBtdXRhdGUoc3BlZWQgPSAoYWlyX3RpbWUgJS8lIDEwMCAqIDYwICogNjAgKyBhaXJfdGltZSAlJSAxMDAgKiA2MCkgLyBkaXN0YW5jZSkgJT4lCiAgZ3JvdXBfYnkoZGVzdCkgJT4lCiAgbXV0YXRlKG1heF9zcGVlZCA9IG1heChzcGVlZCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgbWVkX3NwZWVkID0gbWVkaWFuKHNwZWVkLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICBwcm9wID0gbWF4X3NwZWVkIC8gbWVkX3NwZWVkKSAlPiUKICBhcnJhbmdlKGRlc2MocHJvcCkpCgpmbGlnaHRzIDwtIGZsaWdodHMgJT4lIG11dGF0ZSgKICBkZXBfdGltZSA9IGhvdXIgKiA2MCArIG1pbnV0ZSwKICBhcnJfdGltZSA9IChhcnJfdGltZSAlLyUgMTAwKSAqIDYwICsgKGFycl90aW1lICUlIDEwMCksCiAgYWlydGltZTIgPSBhcnJfdGltZSAtIGRlcF90aW1lLAogIGRlcF9zY2hlZCA9IGRlcF90aW1lICsgZGVwX2RlbGF5CikKCmdncGxvdChmbGlnaHRzLCBhZXMoZGVwX3NjaGVkKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDYwKQpnZ3Bsb3QoZmxpZ2h0cywgYWVzKGRlcF9zY2hlZCAlJSA2MCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKQpnZ3Bsb3QoZmxpZ2h0cywgYWVzKGFpcl90aW1lIC0gYWlydGltZTIpKSArIGdlb21faGlzdG9ncmFtKCkKYGBgICAKCioqKgoKCgo3LiAgRmluZCBhbGwgZGVzdGluYXRpb25zIHRoYXQgYXJlIGZsb3duIGJ5IGF0IGxlYXN0IHR3byBjYXJyaWVycy4gVXNlIHRoYXQKaW5mb3JtYXRpb24gdG8gcmFuayB0aGUgY2FycmllcnMuCgoqKgoKYGBge3IgNS43LjEuNy4xfQpmbGlnaHRzICU+JQogIGdyb3VwX2J5KGRlc3QpICU+JQogIGZpbHRlcihuX2Rpc3RpbmN0KGNhcnJpZXIpID4gMikgJT4lCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lCiAgZmlsdGVyKHJhbmsoYXJyX2RlbGF5KSA8IDEwKQpgYGAKCioqKgoKOC4gRm9yIGVhY2ggcGxhbmUsIGNvdW50IHRoZSBudW1iZXIgb2YgZmxpZ2h0cyBiZWZvcmUgdGhlIGZpcnN0IGRlbGF5IApvZiBncmVhdGVyIHRoYW4gMSBob3VyLgoKKioKCmBgYHtyIDUuNy4xLjh9CmZsaWdodHMgJT4lCiAgbXV0YXRlKGlzX2RlbGF5ZWQgPSBhcnJfZGVsYXkgPiA2MCkgJT4lCiAgZ3JvdXBfYnkodGFpbG51bSkgJT4lCiAgYXJyYW5nZShhcnJfdGltZSkgJT4lCiAgbXV0YXRlKGZpcnN0X2RlbGF5ID0gaWZlbHNlKGlzX2RlbGF5ZWQgPT0gVFJVRSwgaXNfZGVsYXllZCwgTkEpLAogICAgICAgICBmaXJzdF9kZWxheSA9IHJvd19udW1iZXIoZmlyc3RfZGVsYXkpKSAlPiUKICBmaWx0ZXIoaXMubmEoZmlyc3RfZGVsYXkpKSAlPiUKICBncm91cF9ieSh0YWlsbnVtKSAlPiUKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lCiAgYXJyYW5nZShkZXNjKG4pKQoKCiMjIyMjIyMjIyMjIyMjIyMKZmxpZ2h0cyAlPiUKICBtdXRhdGUoZGVwX2RhdGUgPSB0aW1lX2hvdXIpICU+JQogIGdyb3VwX2J5KHRhaWxudW0pICU+JQogIGFycmFuZ2UoZGVwX2RhdGUpICU+JQogIG11dGF0ZShjdW11bGF0aXZlID0gIWN1bWFueShhcnJfZGVsYXkgPiA2MCkpICU+JQogIGZpbHRlcihjdW11bGF0aXZlID09IFQpICU+JQogIHRhbGx5KHNvcnQgPSBUUlVFKQoKYGBgCg==